// 
//    Copyright 2010 The JaernCloud Project
// 
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
// 
//        http://www.apache.org/licenses/LICENSE-2.0
// 
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
// 
using System;
using JaernCloud.Language.Compiler.Ast;

namespace JaernCloud.Language.Compiler {



public partial class Parser {
	public const int _EOF = 0;
	public const int _ident = 1;
	public const int _contextualIdent = 2;
	public const int _tagWithId = 3;
	public const int _tagWithClass = 4;
	public const int _intCon = 5;
	public const int _realCon = 6;
	public const int _charCon = 7;
	public const int _stringCon = 8;
	public const int _blank = 9;
	public const int _http = 10;
	public const int _https = 11;
	public const int _GET = 12;
	public const int _POST = 13;
	public const int _PUT = 14;
	public const int _DELETE = 15;
	public const int _ajax = 16;
	public const int _async = 17;
	public const int _separator = 18;
	public const int _before = 19;
	public const int _after = 20;
	public const int _between = 21;
	public const int _if = 22;
	public const int _foreach = 23;
	public const int _from = 24;
	public const int _where = 25;
	public const int _join = 26;
	public const int _on = 27;
	public const int _equals = 28;
	public const int _into = 29;
	public const int _let = 30;
	public const int _orderby = 31;
	public const int _ascending = 32;
	public const int _descending = 33;
	public const int _select = 34;
	public const int _group = 35;
	public const int _by = 36;
	public const int _take = 37;
	public const int _create = 38;
	public const int _read = 39;
	public const int _update = 40;
	public const int _delete = 41;
	public const int _using = 42;
	public const int _bind = 43;
	public const int _to = 44;
	public const int _in = 45;
	public const int _conversation = 46;
	public const int _request = 47;
	public const int _session = 48;
	public const int _application = 49;
	public const int _not = 50;
	public const int _and = 51;
	public const int _or = 52;
	public const int _null = 53;
	public const int _true = 54;
	public const int _false = 55;
	public const int _colon = 56;
	public const int _comma = 57;
	public const int _selector = 58;
	public const int _globalselector = 59;
	public const int _begin = 60;
	public const int _semicolon = 61;
	public const int _end = 62;
	public const int _nodeid = 63;
	public const int _nodeclass = 64;
	public const int _nodeaction = 65;
	public const int _nodeevent = 66;
	public const int _nodetemplate = 67;
	public const int _assign = 68;
	public const int _intsequence = 69;
	public const int _frontslash = 70;
	public const int _wildcard = 71;
	public const int _nodeparam = 72;
	public const int _notop = 73;
	public const int _andop = 74;
	public const int _orop = 75;
	public const int _lbrack = 76;
	public const int _rbrack = 77;
	public const int _inc = 78;
	public const int _dec = 79;
	public const int _plus = 80;
	public const int _minus = 81;
	public const int _times = 82;
	public const int _module = 83;
	public const int _eq = 84;
	public const int _gt = 85;
	public const int _gteq = 86;
	public const int _lteq = 87;
	public const int _lt = 88;
	public const int _neq = 89;
	public const int _backslash = 90;
	public const int _lpar = 91;
	public const int _rpar = 92;
	public const int maxT = 93;

	const bool T = true;
	const bool x = false;
	const int minErrDist = 2;
	
	public Scanner scanner;
	public Errors  errors;

	public Token t;    // last recognized token
	public Token la;   // lookahead token
	int errDist = minErrDist;



	public Parser(Scanner scanner) {
		this.scanner = scanner;
		errors = new Errors();
	}

	void SynErr (int n) {
		if (errDist >= minErrDist) errors.SynErr(la.line, la.col, n);
		errDist = 0;
	}

	public void SemErr (string msg) {
		if (errDist >= minErrDist) errors.SemErr(t.line, t.col, msg);
		errDist = 0;
	}
	
	void Get () {
		for (;;) {
			t = la;
			la = scanner.Scan();
			if (la.kind <= maxT) { ++errDist; break; }

			la = t;
		}
	}
	
	void Expect (int n) {
		if (la.kind==n) Get(); else { SynErr(n); }
	}
	
	bool StartOf (int s) {
		return set[s, la.kind];
	}
	
	void ExpectWeak (int n, int follow) {
		if (la.kind == n) Get();
		else {
			SynErr(n);
			while (!StartOf(follow)) Get();
		}
	}


	bool WeakSeparator(int n, int syFol, int repFol) {
		int kind = la.kind;
		if (kind == n) {Get(); return true;}
		else if (StartOf(repFol)) {return false;}
		else {
			SynErr(n);
			while (!(set[syFol, kind] || set[repFol, kind] || set[0, kind])) {
				Get();
				kind = la.kind;
			}
			return StartOf(syFol);
		}
	}

	
	void JaernCloud() {
		Root = new AstNode(); AstNode parent = Root; 
		while (StartOf(1)) {
			NodeDecl(parent);
		}
		Expect(0);
	}

	void NodeDecl(AstNode parent) {
		AstNode nodeDecl = new AstNode(); parent.Children.Add(nodeDecl); nodeDecl.Parent = parent; 
		if (StartOf(2)) {
			AstConstantOperator op = AstConstantOperator.Value; 
			NodeConstant(nodeDecl, op);
		} else if (la.kind == 65) {
			NodeWithAction(nodeDecl);
		} else if (IsNodeWithSelector()) {
			NodeWithSelector(nodeDecl);
		} else if (IsNodeWithBody()) {
			NodeWithBody(nodeDecl);
		} else if (la.kind == 1 || la.kind == 2 || la.kind == 4) {
			AstExpression expr; 
			NodeExpression(out expr);
			nodeDecl.Expression = expr; 
		} else SynErr(94);
	}

	void NodeConstant(AstNode nodeDecl, AstConstantOperator op) {
		switch (la.kind) {
		case 53: {
			Get();
			AstUtils.ApplyConstant(op, AstConstantValueKind.Constant, AstConstant.Null, nodeDecl, t); 
			break;
		}
		case 54: {
			Get();
			AstUtils.ApplyConstant(op, AstConstantValueKind.Constant, AstConstant.True, nodeDecl, t); 
			break;
		}
		case 55: {
			Get();
			AstUtils.ApplyConstant(op, AstConstantValueKind.Constant, AstConstant.False, nodeDecl, t); 
			break;
		}
		case 8: {
			Get();
			AstUtils.ApplyConstant(op, AstConstantValueKind.String, AstConstant.Undefined, nodeDecl, t); 
			break;
		}
		case 5: {
			Get();
			AstUtils.ApplyConstant(op, AstConstantValueKind.Integer, AstConstant.Undefined, nodeDecl, t); 
			break;
		}
		case 6: {
			Get();
			AstUtils.ApplyConstant(op, AstConstantValueKind.Float, AstConstant.Undefined, nodeDecl, t); 
			break;
		}
		default: SynErr(95); break;
		}
	}

	void NodeWithAction(AstNode nodeDecl) {
		Expect(65);
		nodeDecl.IsAction = true; 
		if (la.kind == 16 || la.kind == 17) {
			if (la.kind == 16) {
				Get();
				nodeDecl.IsAjax = true; 
			} else {
				Get();
				nodeDecl.IsAsync = true; 
			}
		}
		Expect(1);
		nodeDecl.Tag = AstTag.FromIdent(t); 
		if (la.kind == 60) {
			Get();
			while (StartOf(1)) {
				NodeDecl(nodeDecl);
			}
			Expect(62);
		}
	}

	void NodeWithSelector(AstNode nodeDecl) {
		AstTag tag; 
		if (la.kind == 1 || la.kind == 3 || la.kind == 4) {
			NodeTag(out tag);
			nodeDecl.Tag = tag; 
		}
		Expect(56);
		if (IsNodeInheritsFromSingle()) {
			NodeInheritsFromSingle(nodeDecl);
		} else if (StartOf(3)) {
			NodeInheritsFrom(nodeDecl);
			NodeBounds(nodeDecl);
		} else SynErr(96);
	}

	void NodeWithBody(AstNode nodeDecl) {
		AstTag tag; 
		NodeTag(out tag);
		nodeDecl.Tag = tag; 
		if (HasBody()) {
			if (la.kind == 22 || la.kind == 23) {
				NodeOperator(nodeDecl);
			}
		} else if (la.kind == 22 || la.kind == 23) {
			NodeOperator(nodeDecl);
		} else SynErr(97);
		if (HasQueryOperator(nodeDecl)) {
			if (la.kind == 60) {
				NodeBody(nodeDecl);
			}
		} else if (la.kind == 60) {
			NodeBody(nodeDecl);
		} else SynErr(98);
	}

	void NodeExpression(out AstExpression expr) {
		expr = null; 
		if (la.kind == 4) {
			Get();
			expr = AstPropertyExpression.FromTagWithClass(t.val); 
		} else if (la.kind == 2) {
			Get();
			expr = AstPropertyExpression.FromIdent(t.val); 
		} else if (la.kind == 1) {
			Get();
			expr = AstPropertyExpression.FromIdent(t.val); 
		} else SynErr(99);
		while (la.kind == 64) {
			Get();
			Expect(1);
			(expr as AstPropertyExpression).PropertyNames.Add(t.val); 
		}
		if (la.kind == 78 || la.kind == 79) {
			if (la.kind == 78) {
				Get();
				(expr as AstPropertyExpression).Operator = AstOperator.Increment; 
			} else {
				Get();
				(expr as AstPropertyExpression).Operator = AstOperator.Decrement; 
			}
		}
		if (la.kind == 61) {
			Get();
		}
	}

	void NodeTag(out AstTag tag) {
		tag = null; 
		if (la.kind == 1) {
			Get();
			tag = AstTag.FromIdent(t); 
		} else if (la.kind == 3) {
			Get();
			tag = AstTag.FromWithId(t); 
		} else if (la.kind == 4) {
			Get();
			tag = AstTag.FromWithClass(t); 
		} else SynErr(100);
	}

	void NodeOperator(AstNode nodeDecl) {
		if (la.kind == 22) {
			IfQueryOperator(nodeDecl);
		} else if (la.kind == 23) {
			ForeachQueryOperator(nodeDecl);
		} else SynErr(101);
	}

	void NodeBody(AstNode nodeDecl) {
		Expect(60);
		while (StartOf(1)) {
			NodeDecl(nodeDecl);
		}
		Expect(62);
	}

	void IfQueryOperator(AstNode nodeDecl) {
		Expect(22);
		AstIfQueryOperator query = new AstIfQueryOperator(); nodeDecl.Query = query; 
		AstExpression expr; 
		BooleanNodeExpression(out expr);
		query.Node.Expression = expr; 
	}

	void ForeachQueryOperator(AstNode nodeDecl) {
		Expect(23);
		AstForeachQueryOperator query = new AstForeachQueryOperator(); nodeDecl.Query = query; 
		if (la.kind == 91) {
			Get();
			if (HasForeachIn()) {
				Expect(1);
				query.Identifier = t.val; 
				Expect(45);
			}
			NodeWithBody(query.Node);
			Expect(92);
		} else if (StartOf(4)) {
			if (HasForeachIn()) {
				Expect(1);
				query.Identifier = t.val; 
				Expect(45);
			}
			if (la.kind == 3) {
				Get();
				query.Node.Tag = AstTag.FromWithId(t); 
			} else if (la.kind == 1 || la.kind == 2 || la.kind == 4) {
				AstExpression expr; 
				NodeExpression(out expr);
				query.Node.Expression = expr; 
			} else SynErr(102);
		} else SynErr(103);
	}

	void BooleanNodeExpression(out AstExpression expression) {
		AstBooleanExpression expr = new AstBooleanExpression(); expression = expr; 
		AstExpression left; 
		if (la.kind == 1 || la.kind == 2 || la.kind == 4) {
			NodeExpression(out left);
			expr.Left = left; 
		} else if (StartOf(2)) {
			ConstantExpression(out left);
			expr.Left = left; 
		} else SynErr(104);
		if (la.kind == 84 || la.kind == 89) {
			if (la.kind == 84) {
				Get();
				expr.Operator = AstRelationalOperator.Equal; 
			} else {
				Get();
				expr.Operator = AstRelationalOperator.NotEqual; 
			}
			AstExpression right; 
			if (la.kind == 1 || la.kind == 2 || la.kind == 4) {
				NodeExpression(out right);
				expr.Right = right; 
			} else if (StartOf(2)) {
				ConstantExpression(out right);
				expr.Right = right; 
			} else SynErr(105);
		}
	}

	void ConstantExpression(out AstExpression expr) {
		expr = null; 
		switch (la.kind) {
		case 53: {
			Get();
			expr = new AstNullConstantExpression(); 
			break;
		}
		case 54: {
			Get();
			expr = AstBooleanConstantExpression.True; 
			break;
		}
		case 55: {
			Get();
			expr = AstBooleanConstantExpression.False; 
			break;
		}
		case 8: {
			Get();
			expr = AstStringConstantExpression.FromToken(t); 
			break;
		}
		case 5: {
			Get();
			expr = AstIntegerConstantExpression.FromToken(t); 
			break;
		}
		case 6: {
			Get();
			expr = AstFloatConstantExpression.FromToken(t); 
			break;
		}
		default: SynErr(106); break;
		}
	}

	void NodeBounds(AstNode nodeDecl) {
		if (la.kind == 61) {
			Get();
		} else if (la.kind == 60) {
			NodeBody(nodeDecl);
		} else SynErr(107);
	}

	void NodeInheritsFrom(AstNode nodeDecl) {
		AstConstantOperator op = AstConstantOperator.InheritsFrom; 
		if (StartOf(2)) {
			NodeConstant(nodeDecl, op);
		} else if (la.kind == 1 || la.kind == 3 || la.kind == 4) {
			NodeSelectorList(nodeDecl);
		} else SynErr(108);
	}

	void NodeSelectorList(AstNode nodeDecl) {
		AstTagSelector selector; 
		NodeSelector(out selector);
		nodeDecl.InheritsFrom.Add(new AstInheritsFrom(selector)); 
		while (la.kind == 57) {
			Get();
			NodeSelector(out selector);
			nodeDecl.InheritsFrom.Add(new AstInheritsFrom(selector)); 
		}
	}

	void NodeInheritsFromSingle(AstNode nodeDecl) {
		AstConstantOperator op = AstConstantOperator.InheritsFrom; 
		if (StartOf(2)) {
			NodeConstant(nodeDecl, op);
		} else if (la.kind == 1 || la.kind == 3 || la.kind == 4) {
			AstTag tag; 
			NodeTag(out tag);
			nodeDecl.InheritsFrom.Add(new AstInheritsFrom(tag)); 
		} else SynErr(109);
		if (la.kind == 61) {
			Get();
		}
	}

	void NodeSelector(out AstTagSelector selector) {
		AstTag tag; 
		NodeTag(out tag);
		selector = new AstTagSelector(tag); 
		while (la.kind == 1 || la.kind == 3 || la.kind == 4) {
			NodeTag(out tag);
			selector.Tags.Add(tag); 
		}
	}



	public void Parse() {
		la = new Token();
		la.val = "";		
		Get();
		JaernCloud();

    Expect(0);
	}
	
	static readonly bool[,] set = {
		{T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
		{x,T,T,T, T,T,T,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,T, T,x,x,x, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
		{x,x,x,x, x,T,T,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
		{x,T,x,T, T,T,T,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
		{x,T,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x}

	};
} // end Parser


public class Errors {
	public int count = 0;                                    // number of errors detected
	public System.IO.TextWriter errorStream = Console.Out;   // error messages go to this stream
  public string errMsgFormat = "-- line {0} col {1}: {2}"; // 0=line, 1=column, 2=text
  
	public void SynErr (int line, int col, int n) {
		string s;
		switch (n) {
			case 0: s = "EOF expected"; break;
			case 1: s = "ident expected"; break;
			case 2: s = "contextualIdent expected"; break;
			case 3: s = "tagWithId expected"; break;
			case 4: s = "tagWithClass expected"; break;
			case 5: s = "intCon expected"; break;
			case 6: s = "realCon expected"; break;
			case 7: s = "charCon expected"; break;
			case 8: s = "stringCon expected"; break;
			case 9: s = "blank expected"; break;
			case 10: s = "http expected"; break;
			case 11: s = "https expected"; break;
			case 12: s = "GET expected"; break;
			case 13: s = "POST expected"; break;
			case 14: s = "PUT expected"; break;
			case 15: s = "DELETE expected"; break;
			case 16: s = "ajax expected"; break;
			case 17: s = "async expected"; break;
			case 18: s = "separator expected"; break;
			case 19: s = "before expected"; break;
			case 20: s = "after expected"; break;
			case 21: s = "between expected"; break;
			case 22: s = "if expected"; break;
			case 23: s = "foreach expected"; break;
			case 24: s = "from expected"; break;
			case 25: s = "where expected"; break;
			case 26: s = "join expected"; break;
			case 27: s = "on expected"; break;
			case 28: s = "equals expected"; break;
			case 29: s = "into expected"; break;
			case 30: s = "let expected"; break;
			case 31: s = "orderby expected"; break;
			case 32: s = "ascending expected"; break;
			case 33: s = "descending expected"; break;
			case 34: s = "select expected"; break;
			case 35: s = "group expected"; break;
			case 36: s = "by expected"; break;
			case 37: s = "take expected"; break;
			case 38: s = "create expected"; break;
			case 39: s = "read expected"; break;
			case 40: s = "update expected"; break;
			case 41: s = "delete expected"; break;
			case 42: s = "using expected"; break;
			case 43: s = "bind expected"; break;
			case 44: s = "to expected"; break;
			case 45: s = "in expected"; break;
			case 46: s = "conversation expected"; break;
			case 47: s = "request expected"; break;
			case 48: s = "session expected"; break;
			case 49: s = "application expected"; break;
			case 50: s = "not expected"; break;
			case 51: s = "and expected"; break;
			case 52: s = "or expected"; break;
			case 53: s = "null expected"; break;
			case 54: s = "true expected"; break;
			case 55: s = "false expected"; break;
			case 56: s = "colon expected"; break;
			case 57: s = "comma expected"; break;
			case 58: s = "selector expected"; break;
			case 59: s = "globalselector expected"; break;
			case 60: s = "begin expected"; break;
			case 61: s = "semicolon expected"; break;
			case 62: s = "end expected"; break;
			case 63: s = "nodeid expected"; break;
			case 64: s = "nodeclass expected"; break;
			case 65: s = "nodeaction expected"; break;
			case 66: s = "nodeevent expected"; break;
			case 67: s = "nodetemplate expected"; break;
			case 68: s = "assign expected"; break;
			case 69: s = "intsequence expected"; break;
			case 70: s = "frontslash expected"; break;
			case 71: s = "wildcard expected"; break;
			case 72: s = "nodeparam expected"; break;
			case 73: s = "notop expected"; break;
			case 74: s = "andop expected"; break;
			case 75: s = "orop expected"; break;
			case 76: s = "lbrack expected"; break;
			case 77: s = "rbrack expected"; break;
			case 78: s = "inc expected"; break;
			case 79: s = "dec expected"; break;
			case 80: s = "plus expected"; break;
			case 81: s = "minus expected"; break;
			case 82: s = "times expected"; break;
			case 83: s = "module expected"; break;
			case 84: s = "eq expected"; break;
			case 85: s = "gt expected"; break;
			case 86: s = "gteq expected"; break;
			case 87: s = "lteq expected"; break;
			case 88: s = "lt expected"; break;
			case 89: s = "neq expected"; break;
			case 90: s = "backslash expected"; break;
			case 91: s = "lpar expected"; break;
			case 92: s = "rpar expected"; break;
			case 93: s = "??? expected"; break;
			case 94: s = "invalid NodeDecl"; break;
			case 95: s = "invalid NodeConstant"; break;
			case 96: s = "invalid NodeWithSelector"; break;
			case 97: s = "invalid NodeWithBody"; break;
			case 98: s = "invalid NodeWithBody"; break;
			case 99: s = "invalid NodeExpression"; break;
			case 100: s = "invalid NodeTag"; break;
			case 101: s = "invalid NodeOperator"; break;
			case 102: s = "invalid ForeachQueryOperator"; break;
			case 103: s = "invalid ForeachQueryOperator"; break;
			case 104: s = "invalid BooleanNodeExpression"; break;
			case 105: s = "invalid BooleanNodeExpression"; break;
			case 106: s = "invalid ConstantExpression"; break;
			case 107: s = "invalid NodeBounds"; break;
			case 108: s = "invalid NodeInheritsFrom"; break;
			case 109: s = "invalid NodeInheritsFromSingle"; break;

			default: s = "error " + n; break;
		}
		errorStream.WriteLine(errMsgFormat, line, col, s);
		count++;
	}

	public void SemErr (int line, int col, string s) {
		errorStream.WriteLine(errMsgFormat, line, col, s);
		count++;
	}
	
	public void SemErr (string s) {
		errorStream.WriteLine(s);
		count++;
	}
	
	public void Warning (int line, int col, string s) {
		errorStream.WriteLine(errMsgFormat, line, col, s);
	}
	
	public void Warning(string s) {
		errorStream.WriteLine(s);
	}
} // Errors


public class FatalError: Exception {
	public FatalError(string m): base(m) {}
}

}